//! 模式匹配示例
//!
//! match 允许我们将一个值与一系列模式进行比较并执行相应的代码
//!
//! 模式由以下元素组成：
//! - 字面值
//! - 解构的数组、枚举、结构体和元组
//! - 变量
//! - 通配符
//! - 占位符

/// 基础模式匹配
///
/// match 类似于其他语言中的 switch 语句，但功能更强大
#[allow(dead_code)]
enum Coin {
    Penny,
    Nickel,
    Dime,
    Quarter,
}

#[test]
pub fn match_basics() {
    fn value_in_cents(coin: Coin) -> u8 {
        match coin {
            Coin::Penny => {
                println!("幸运 penny!");
                1
            },
            Coin::Nickel => 5,
            Coin::Dime => 10,
            Coin::Quarter => 25,
        }
    }

    let coin_value = value_in_cents(Coin::Dime);
    println!("Dime 的价值: {coin_value} 分");
}

/// 匹配 `Option<T>` 类型
///
/// match 对 `Option<T>` 类型特别有用
#[test]
pub fn matching_option() {
    fn plus_one(x: Option<i32>) -> Option<i32> {
        match x {
            None => None,
            Some(i) => Some(i + 1),
        }
    }

    let five = Some(5);
    let six = plus_one(five);
    let none = plus_one(None);

    println!("匹配 Option 示例:");
    println!("5 + 1 = {six:?}");
    println!("None + 1 = {none:?}");
}

/// 使用 _ 通配符
///
/// _ 模式会匹配所有可能的值
#[test]
pub fn wildcard_pattern() {
    let some_u8_value = 0u8;

    match some_u8_value {
        1 => println!("一"),
        3 => println!("三"),
        5 => println!("五"),
        7 => println!("七"),
        _ => println!("其他值"), // _ 会匹配所有其他情况
    }
}

/// if let 简洁控制流
///
/// if let 语法让我们只关心一种匹配模式，而忽略其他所有模式
#[test]
pub fn if_let_control() {
    let some_u8_value = Some(0u8);

    // 使用 match
    match some_u8_value {
        Some(3) => println!("匹配到了三"),
        _ => (), // 忽略其他所有情况
    }

    // 使用 if let 简化代码
    if let Some(3) = some_u8_value {
        println!("匹配到了三");
    }

    // if let 也可以包含 else
    let another_u8_value = Some(5u8);
    if let Some(3) = another_u8_value {
        println!("匹配到了三");
    } else {
        println!("没有匹配到三");
    }
}

/// 模式匹配的所有形式
///
/// Rust 中的模式匹配有多种形式
#[test]
pub fn pattern_matching_forms() {
    println!("\n=== 模式匹配的所有形式 ===");

    // 1. 字面值模式
    let x = 1;
    match x {
        1 => println!("一"),
        2 => println!("二"),
        3 => println!("三"),
        _ => println!("其他"),
    }

    // 2. 命名变量模式
    let x = Some(5);
    match x {
        Some(i) => println!("匹配到 {i:?}"),
        None => println!("没有匹配到值"),
    }

    // 3. 多个模式
    let x = 1;
    match x {
        1 | 2 => println!("一或二"),
        3 => println!("三"),
        _ => println!("其他"),
    }

    // 4. 匹配范围
    let x = 5;
    match x {
        1..=5 => println!("一到五之间"),
        _ => println!("其他"),
    }

    // 5. 解构结构体
    struct Point {
        x: i32,
        y: i32,
    }

    let p = Point { x: 0, y: 7 };
    let Point { x: a, y: b } = p;
    println!("解构结构体: ({a}, {b})");

    // 6. 解构枚举
    #[derive(Debug)]
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let msg = Message::ChangeColor(0, 160, 255);
    match msg {
        Message::Quit => println!("退出"),
        Message::Move { x, y } => println!("移动到 ({x}, {y})"),
        Message::Write(text) => println!("写入文本: {text}"),
        Message::ChangeColor(r, g, b) => println!("颜色变化为 ({r}, {g}, {b})"),
    }

    // 7. 解构嵌套结构
    enum Color {
        Rgb(i32, i32, i32),
        Hsv(i32, i32, i32),
    }

    enum Message2 {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(Color),
    }

    let msg = Message2::ChangeColor(Color::Hsv(0, 160, 255));
    match msg {
        Message2::ChangeColor(Color::Hsv(h, s, v)) => {
            println!("颜色模式: HSV({h}, {s}, {v})")
        },
        _ => (),
    }

    // 8. 忽略值的模式
    let numbers = (2, 4, 8, 16, 32);
    match numbers {
        (first, _, third, _, fifth) => {
            println!("获取第1、3、5个值: {first}, {third}, {fifth}");
        },
    }

    // 9. 使用 .. 忽略剩余值
    struct Point3D {
        x: i32,
        y: i32,
        z: i32,
    }

    let origin = Point3D { x: 0, y: 0, z: 0 };
    match origin {
        Point3D { x, .. } => println!("只获取 x 坐标: {x}"),
    }

    // 10. 匹配守卫
    let num = Some(4);
    match num {
        Some(x) if x < 5 => println!("小于 5 的数字: {x}"),
        Some(x) => println!("大于等于 5 的数字: {x}"),
        None => (),
    }

    // 11. @ 绑定
    #[derive(Debug)]
    enum Message3 {
        Hello { id: i32 },
    }

    let msg = Message3::Hello { id: 5 };
    match msg {
        Message3::Hello { id: id_variable @ 3..=7 } => {
            println!("找到一个 ID 在范围内的消息: {id_variable:?}")
        },
        Message3::Hello { id: 10..=12 } => {
            println!("找到一个 ID 在另一个范围内的消息")
        },
        Message3::Hello { id } => {
            println!("找到其他消息，ID 为: {id}")
        },
    }
}

/// 模式匹配在其他控制流中的应用
///
/// 模式匹配不仅限于 match 语句
#[test]
pub fn patterns_in_control_flow() {
    println!("\n=== 模式匹配在其他控制流中的应用 ===");

    // 1. 在 if let 中使用模式
    let favorite_color: Option<&str> = None;
    if let Some(color) = favorite_color {
        println!("最喜欢的颜色是 {color}");
    } else {
        println!("没有最喜欢的颜色");
    }

    // 2. 在 while let 中使用模式
    let mut stack = Vec::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);

    while let Some(top) = stack.pop() {
        println!("取出元素: {top}");
    }

    // 3. 在 for 循环中使用模式
    let v = vec!['a', 'b', 'c'];
    for (index, value) in v.iter().enumerate() {
        println!("{index} 位置是 {value}");
    }

    // 4. 在 let 语句中使用模式
    let (x, y, z) = (1, 2, 3);
    println!("解构元组: {x}, {y}, {z}");

    // 5. 在函数参数中使用模式
    fn print_coordinates(&(x, y): &(i32, i32)) {
        println!("当前坐标: ({x}, {y})");
    }

    let point = (3, 5);
    print_coordinates(&point);
}

/// 高级模式匹配技巧
///
/// 展示一些更高级的模式匹配用法
#[test]
pub fn advanced_pattern_matching() {
    println!("\n=== 高级模式匹配技巧 ===");

    // 匹配守卫 (Match Guards)
    // 匹配守卫是一个指定于 match 分支模式之后的额外 if 条件
    let num = Some(4);
    match num {
        Some(x) if x < 5 => println!("小于 5 的数字: {x}"),
        Some(x) => println!("大于等于 5 的数字: {x}"),
        None => (),
    }

    // 使用匹配守卫解决变量遮蔽问题
    let x = Some(5);
    let y = 10;
    match x {
        Some(50) => println!("Got 50"),
        Some(n) if n == y => println!("Matched, n = {n}"),
        _ => println!("Default case, x = {x:?}"),
    }

    // @ 绑定 (At bindings)
    // @ 操作符允许我们在匹配模式的同时创建一个变量来保存整个值
    #[derive(Debug)]
    enum Color {
        Rgb(i32, i32, i32),
        Hsv(i32, i32, i32),
    }

    enum Message {
        ChangeColor(Color),
    }

    let msg = Message::ChangeColor(Color::Rgb(0, 160, 255));
    match msg {
        Message::ChangeColor(Color::Rgb(r, g, b)) if r == 0 => {
            println!("颜色模式: RGB({r}, {g}, {b}) - 红色分量为0")
        },
        Message::ChangeColor(color) => {
            println!("颜色值: {color:?}")
        },
    }
}

/// if let 表达式
///
/// if let 语法让我们只关心一种匹配模式，而忽略其他所有模式
#[test]
pub fn if_let_expressions() {
    println!("\n=== if let 表达式 ===");

    let some_value: Option<i32> = Some(3);

    // 使用 match 处理 Option
    match some_value {
        Some(3) => println!("匹配到了三"),
        _ => (), // 忽略其他所有情况
    }

    // 使用 if let 简化代码
    if let Some(3) = some_value {
        println!("匹配到了三");
    }

    // if let 也可以包含 else
    let another_value = Some(5);
    if let Some(3) = another_value {
        println!("匹配到了三");
    } else {
        println!("没有匹配到三");
    }

    // 处理枚举值
    #[derive(Debug)]
    enum Message {
        Quit,
        Move { x: i32, y: i32 },
        Write(String),
        ChangeColor(i32, i32, i32),
    }

    let msg = Message::Write(String::from("hello"));
    if let Message::Write(text) = msg {
        println!("文本消息: {text}");
    }
}

/// while let 条件循环
///
/// while let 允许我们在条件为真时重复执行模式匹配和相应的代码块
#[test]
pub fn while_let_loops() {
    println!("\n=== while let 条件循环 ===");

    // 使用 while let 处理 Option 值
    let mut stack = Vec::new();
    stack.push(1);
    stack.push(2);
    stack.push(3);

    while let Some(top) = stack.pop() {
        println!("取出元素: {top}");
    }

    // 使用 while let 处理迭代器
    let vec = vec!['a', 'b', 'c'];
    let iter = vec.iter().enumerate();

    for (index, value) in iter {
        println!("{index} 位置是 {value}");
    }
}

/// 模式在其他位置的应用
///
/// 模式匹配不仅限于 match 语句，还可以用于多种场景
#[test]
pub fn patterns_in_other_places() {
    println!("\n=== 模式在其他位置的应用 ===");

    // 1. 在 let 语句中使用模式
    let (x, y, z) = (1, 2, 3);
    println!("解构元组: {x}, {y}, {z}");

    let (_, second, _) = (1, 2, 3);
    println!("只获取第二个值: {second}");

    // 2. 在函数参数中使用模式
    fn print_coordinates(&(x, y): &(i32, i32)) {
        println!("当前坐标: ({x}, {y})");
    }

    let point = (3, 5);
    print_coordinates(&point);

    // 3. 在 for 循环中使用模式
    let values = vec![(1, 2), (3, 4), (5, 6)];
    for (x, y) in values {
        println!("坐标点: ({x}, {y})");
    }

    // 4. 在闭包参数中使用模式
    let numbers = vec![(1, 2), (3, 4), (5, 6)];
    let sums: Vec<i32> = numbers.iter().map(|(x, y)| x + y).collect();
    println!("元组元素之和: {sums:?}");
}

/// 主演示函数
#[test]
pub fn demonstrate_pattern_matching() {
    match_basics();
    matching_option();
    wildcard_pattern();
    if_let_control();
    pattern_matching_forms();
    patterns_in_control_flow();
    advanced_pattern_matching();
    if_let_expressions();
    while_let_loops();
    patterns_in_other_places();
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_match_basics() {
        match_basics();
    }

    #[test]
    fn test_matching_option() {
        matching_option();
    }

    #[test]
    fn test_wildcard_pattern() {
        wildcard_pattern();
    }

    #[test]
    fn test_if_let_control() {
        if_let_control();
    }

    #[test]
    fn test_pattern_matching_forms() {
        pattern_matching_forms();
    }

    #[test]
    fn test_patterns_in_control_flow() {
        patterns_in_control_flow();
    }
}
